﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using PivotalTFSSync;

namespace PivotalTrackerAPI
{
	public class Pivotal : IPivotal
	{
		#region IterationVersion enum

		public enum IterationVersion
		{
			Done = 0,
			Current = 1,
			Backlog = 2,
			All = 3
		}

		#endregion

		private const string BaseURL = "https://www.pivotaltracker.com/services/v3/projects/";
		private const string TokenURL = "https://www.pivotaltracker.com/services/tokens/active";
		private string token = string.Empty;

		public Pivotal(string username, string password)
		{
			Login(username, password);
		}

		#region IPivotal Members

		string IPivotal.AddStory(Project project, IterationVersion iteration, string name, string requestedBy,
		                         string storytype,
		                         string description)
		{
			string url = string.Concat(BaseURL, project.Id, "/stories?token=", token);
			var storyXml = new StringBuilder();

			storyXml.AppendFormat("<story><story_type>{0}</story_type><name>{1}</name><requested_by>{2}</requested_by>",
			                      storytype, name, requestedBy);
			if (!string.IsNullOrEmpty(description))
			{
				storyXml.AppendFormat("<description>{0}</description>", description);
			}
			storyXml.Append("</story>");
			return AddStoryOrTask(url, storyXml.ToString());
		}

		Project IPivotal.GetProjectById(int id)
		{
			return FromXml<Project>(GetPivotalResponse(string.Concat(BaseURL, id)).ToString());
		}

		IEnumerable<Project> IPivotal.GetAllProjects()
		{
			return
				FromXml<Projects>(
					GetPivotalResponse(BaseURL).ToString()).projects;
		}

		IEnumerable<Iteration> IPivotal.GetIteration(Project project, IterationVersion iterationToRetrieve)
		{
			string iterationsfilter = Enum.GetName(typeof (IterationVersion), iterationToRetrieve).ToLower();
			var iterations =
				FromXml<Iterations>(
					GetPivotalResponse(string.Concat(BaseURL, project.Id, "/iterations/", iterationsfilter)).ToString());

			foreach (Iteration iteration in iterations.iterations)
			{
				yield return iteration;
			}
		}

		#endregion

		private void Login(string username, string password)
		{
			var request = (HttpWebRequest) WebRequest.Create(TokenURL);

			// Set the Method property to 'POST' to post data to the URI. 
			request.Method = "POST";

			request.Proxy = WebProxy.GetDefaultProxy();

			byte[] byteArray = Encoding.UTF8.GetBytes(string.Concat("username=", username, "&password=", password));

			request.ContentLength = byteArray.Length;

			Stream dataStream = request.GetRequestStream();
			dataStream.Write(byteArray, 0, byteArray.Length);

			dataStream.Close();
			Stream objStream;
			try
			{
				objStream = request.GetResponse().GetResponseStream();
			}
			catch (Exception)
			{
				//TODO: Show error.

				return;
			}

			StringBuilder sb = GetStringBuilderFromStream(objStream);

			string xml = sb.ToString();
			var xmlDoc = new XmlDocument();

			xmlDoc.LoadXml(xml);

			token = xmlDoc.GetElementsByTagName("guid").Item(0).InnerText;
		}

		private StringBuilder GetStringBuilderFromStream(Stream objStream)
		{
			var objReader = new StreamReader(objStream);

			string sLine = string.Empty;
			var sb = new StringBuilder();

			while (sLine != null)
			{
				sLine = objReader.ReadLine();
				if (sLine != null)
				{
					sb.AppendLine(sLine);
				}
			}
			return sb;
		}

		private StringBuilder GetPivotalResponse(string url)
		{
			var request = (HttpWebRequest) WebRequest.Create(url);

			request.Proxy = WebProxy.GetDefaultProxy();
			request.Headers.Add("X-TrackerToken", token);

			return GetStringBuilderFromStream(request.GetResponse().GetResponseStream());
		}

		//Creates an object from an XML string.
		private static T FromXml<T>(string Xml)
		{
			var ser = new XmlSerializer(typeof (T));
			var stringReader = new StringReader(Xml);
			var xmlReader = new XmlTextReader(stringReader);
			var obj = (T) ser.Deserialize(xmlReader);
			xmlReader.Close();
			stringReader.Close();
			return obj;
		}

		private string AddStoryOrTask(string url, string data)
		{
			var request = (HttpWebRequest) WebRequest.Create(url);

			// Set the ContentType property. 
			request.ContentType = "application/xml";

			// Set the Method property to 'POST' to post data to the URI. 
			request.Method = "POST";

			request.Proxy = WebProxy.GetDefaultProxy();

			byte[] byteArray = Encoding.UTF8.GetBytes(data);

			request.ContentLength = byteArray.Length;
			Stream dataStream = null;
			try
			{
				dataStream = request.GetRequestStream();
				dataStream.Write(byteArray, 0, byteArray.Length);
			}
			catch (Exception ex)
			{
				//TODO: log error.
				return ex.Message;
			}
			finally
			{
				if (dataStream != null)
					dataStream.Close();
			}

			Stream objStream;
			try
			{
				objStream = request.GetResponse().GetResponseStream();
			}
			catch (Exception ex)
			{
				//TODO: logerror
				return ex.Message;
			}

			return GetStringBuilderFromStream(objStream).ToString();
		}
	}
}